﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using com.lover.astd.common.manager;
using mshtml;
using com.lover.astd.game.ui.server;
using com.lover.astd.common.model;
using System.Collections;
using System.Globalization;
using com.lover.common;
using com.lover.astd.common.config;
using System.Reflection;
using com.lover.astd.common.model.enumer;
using Microsoft.Win32;
using com.lover.astd.weaponcalc;
using com.lover.astd.game.ui.ui;
using System.Net;
using com.lover.astd.common.partner;
using com.lover.astd.common.model.battle;
using com.lover.astd.common;
using com.lover.astd.common.logicexe.building;
using com.lover.astd.common.logic;
using com.lover.astd.common.logicexe;
using com.lover.astd.game.ui.server.impl;
using com.lover.astd.game.ui.server.impl.troop;
using com.lover.astd.common.logicexe.hero;
using com.lover.astd.game.ui.server.impl.secretary;
using com.lover.astd.common.logicexe.secretary;
using com.lover.astd.game.ui.server.impl.equipment;
using com.lover.astd.common.logicexe.equip;
using com.lover.astd.game.ui.server.impl.economy;
using com.lover.astd.common.logicexe.economy;
using com.lover.astd.game.ui.server.impl.battle;
using com.lover.astd.common.logicexe.battle;
using com.lover.astd.game.ui.server.impl.activities;
using com.lover.astd.common.logicexe.activities;
using com.lover.astd.common.logicexe.temp;
using com.lover.common.hook;
using com.lover.astd.common.model.building;

namespace com.lover.astd.game.ui
{
    public partial class MainForm : Form, ILogger, IServer
    {
        private string _initialUrl = "http://www.whohelpyou.com/";
        protected LogHelper _logger;
        
        #region inner fields
        private DoKeyHook _keyHook;
        private LogLevel _logLevel = LogLevel.Info;
        private bool _intentExit = false;
        private Timer _serverTimeTimer;
        private Timer _refreshUiTimer;
        private ExeMgr _exeMgr;
        private SettingsMgr _settingMgr;
        private System.Timers.Timer _relogin_timer;
        private System.Threading.Thread _init_thread;
        private System.Threading.Thread _exe_thread;
        /// <summary>
        /// 0=initial, 1=ready for server, 2=server running, 3=server stopped but initialed
        /// </summary>
        private int _serverStatus = 0;
        private string _custome_session = "";
        private AccountData _account;
        /// <summary>
        /// user account entity
        /// </summary>
        public AccountData Account { get { return _account; } }
        public GameConfig getConfig() { if (_account != null) return _account.GameConf; else return null; }
        private User _gameUser;
        /// <summary>
        /// 该账号信息包含的游戏用户信息
        /// </summary>
        public User GameUser
        {
            get { return _gameUser; }
            set { _gameUser = value; }
        }
        public MainForm()
        {
            InitializeComponent();
        }
        public void removeKeyHook()
        {
            HookUtils.removeKeyHook();
        }
        public void setKeyHook(bool shift, bool ctrl, bool alt, Keys key)
        {
            HookUtils.setKeyHook(shift, ctrl, alt, key, _keyHook);
        }
        void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
        {
            SystemEvents.SessionEnding -= SystemEvents_SessionEnding;
            closeMe();
        }
        private void toggleHide()
        {
            if (notify_icon.Visible) { this.Hide(); notify_icon.Visible = false; }
            else { this.Show(); notify_icon.Visible = true; }
        }
        private void MainForm_Load(object sender, EventArgs e)
        {
            _keyHook = new DoKeyHook(toggleHide);
            if (GlobalConfig.getInstance().IsDebug) _logLevel = LogLevel.Debug;
            _gameUser = new User();

            this.Text = GlobalConfig.Version;
            gameBrowser.Navigate(_initialUrl);

            if (!GlobalConfig.getInstance().IsDebug) { menu_test.Visible = false; }

            menu_refresh.Enabled = false;
            menu_startServer.Enabled = false;
            menu_stopServer.Enabled = false;
            menu_default.Enabled = false;

            SystemEvents.SessionEnding += SystemEvents_SessionEnding;

            _serverTimeTimer = new Timer();
            _serverTimeTimer.Interval = 1000;
            _serverTimeTimer.Tick += _serverTimeTimer_Tick;
            _serverTimeTimer.Start();

            _refreshUiTimer = new Timer();
            _refreshUiTimer.Interval = 500;
            _refreshUiTimer.Tick += _refreshUiTimer_Tick;
            _refreshUiTimer.Start();
        }
        void _refreshUiTimer_Tick(object sender, EventArgs e)
        {
            if (_serverStatus == 0)
            {
                menu_startServer.Enabled = true;
                menu_stopServer.Enabled = false;
                if (_account != null && _account.Server_type == ServerType.Custom) menu_init.Enabled = true;
                else menu_init.Enabled = false;
                menu_refresh.Enabled = false;
                menu_default.Enabled = false;
            }
            else if (_serverStatus == 1)
            {
                menu_startServer.Enabled = true;
                menu_stopServer.Enabled = false;
                menu_init.Enabled = true;
                menu_refresh.Enabled = true;
                menu_default.Enabled = true;
            }
            else if (_serverStatus == 2)
            {
                menu_startServer.Enabled = false;
                menu_stopServer.Enabled = true;
                menu_init.Enabled = true;
                menu_refresh.Enabled = true;
                menu_default.Enabled = true;
            }
            else if (_serverStatus == 3)
            {
                menu_startServer.Enabled = true;
                menu_stopServer.Enabled = false;
                menu_init.Enabled = true;
                menu_refresh.Enabled = true;
                menu_default.Enabled = true;
            }
            if (_settingMgr == null) return;
            _refreshUiTimer.Stop();
            _settingMgr.renderSettings();
            if (_exeMgr != null) txt_servers.Text = _exeMgr.Status;
            _refreshUiTimer.Start();
        }
        void _serverTimeTimer_Tick(object sender, EventArgs e)
        {
            DateTime dt = TimeMgr.DateTimeNow;
            lbl_time.Text = dt.ToString("G");
        }
        # endregion

        #region refresh player things
        public void refreshPlayerInfo()
        {
            User u = _gameUser;
            this.Text = String.Format("[{0}] <{1}>",
                String.Format("{0:s}({1:d}) - {2}", u.Username, u.Level, _account.getServerName()), 
                GlobalConfig.Version);
            setPlayerInfoLabelSafe();
            setPlayerInfoNotify();
        }
        private delegate void SetLablePlayerInfoDelegate();
        private void setPlayerInfoLabelSafe()
        {
            if (lbl_playerinfo.InvokeRequired) lbl_playerinfo.Invoke(new SetLablePlayerInfoDelegate(setPlayerInfoLabel));
            else setPlayerInfoLabel();
        }
        private void setPlayerInfoLabel()
        {
            User u = _gameUser;
            lbl_playerinfo.Text = String.Format("{0}[{1}级 {2} {3}{4}] 金币[{5}] 银币[{6}] 玉石[{7}] 军功[{8}] 行动力[{9}] 军令[{10}/50] 攻击令[{11}/50] 城防[{12}] 战绩[{13}]",
                u.Username, u.Level, u.Nation, u.Year, u.SeasonName, u.Gold, CommonUtils.getReadable(u.Silver), CommonUtils.getReadable(u.Stone),
                CommonUtils.getReadable(u.Credit), CommonUtils.getReadable(u.CurMovable), u.Token, u.AttackOrders, u._attack_cityHp, u._attack_battleScore);
        }
        private void setPlayerInfoNotify()
        {
            User u = _gameUser;
            notify_icon.Text = String.Format("{0}{1}区-{2}", EnumString.getString(_account.Server_type), _account.ServerId, u.Username);
        }
        #endregion

        #region event listeners
        private void gameBrowser_NewWindow3(object sender, AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
        {
            gameBrowser.Navigate(e.bstrUrl);
            e.cancel = true;
        }
        private void gameBrowser_NavigateComplete2(object sender, AxSHDocVw.DWebBrowserEvents2_NavigateComplete2Event e)
        {
            if (_account == null || _account.Server_type != ServerType.Custom) return;
            HTMLDocument doc = (HTMLDocument)gameBrowser.Document;
            if (doc == null) return;
            Uri doc_uri = new Uri(doc.url);
            Uri acc_uri = new Uri(_account.CustomGameUrl);
            if(doc_uri.Host.Equals(acc_uri.Host) && doc_uri.AbsolutePath.Equals(acc_uri.AbsolutePath)) getCustomSession();
        }
        private void subBrowser_NavigateComplete2(object sender, AxSHDocVw.DWebBrowserEvents2_NavigateComplete2Event e)
        {
            if (_account == null || _account.Server_type != ServerType.Custom) return;
            HTMLDocument doc = (HTMLDocument)subBrowser.Document;
            if (doc == null) return;
            string cookie_str = doc.cookie;
            if (cookie_str == null) return;
            string[] cookie_strs = cookie_str.Split(';');
            foreach (string subcook_str in cookie_strs)
            {
                if (subcook_str == null) continue;
                string[] keyvalue = subcook_str.Split('=');
                if (keyvalue.Length < 2) continue;
                if (keyvalue[0].Equals("JSESSIONID"))
                {
                    _custome_session = keyvalue[1];
                    _jsessionid = _custome_session;
                    _gameurl = _account.CustomGameUrl;

                    start_delay_init();
                    break;
                }
            }
        }
        private void menu_init_Click(object sender, EventArgs e)
        {
            if (_account == null) return;
            if (_account.Server_type == ServerType.Custom)
            {
                if (_custome_session == null || _custome_session.Length == 0)
                {
                    getCustomSession();
                    return;
                }
            }
            start_delay_init(true);
        }
        private void menu_startServer_Click(object sender, EventArgs e)
        {
            if (_account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            menu_startServer.Enabled = false;
            menu_stopServer.Enabled = true;
            startServer();
        }
        private void menu_stopServer_Click(object sender, EventArgs e)
        {
            if (_account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            menu_startServer.Enabled = true;
            menu_stopServer.Enabled = false;
            stopServer(true);
        }
        
        private void menu_refresh_Click(object sender, EventArgs e)
        {
            if (_account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            gameBrowser.Navigate(_gameurl);
        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!_intentExit) { this.Hide(); e.Cancel = true; }
        }
        private void menu_saveSettings_Click(object sender, EventArgs e)
        {
            // 首先validate, 否则会导致datagridview中的未失去焦点的数据提交不了
            this.Validate();
            // collect settings
            if (_settingMgr == null || _account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            _settingMgr.saveSettings();
            _account.GameConf.saveSettings();
            _account.GameConf.loadSettings();
            UiUtils.getInstance().info("保存设置成功");
        }
        private void menu_default_Click(object sender, EventArgs e)
        {
            if (_settingMgr == null || _account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            DialogResult result = MessageBox.Show("你确定要恢复默认设置吗?", "确认信息", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
            if (result == DialogResult.Yes)
            {
                // collect settings
                _settingMgr.loadDefaultSettings();
                _account.GameConf.saveSettings();
                _account.GameConf.loadSettings();
                UiUtils.getInstance().info("保存设置成功");
            }
        }
        private void menu_relogin_Click(object sender, EventArgs e)
        {
            if (_settingMgr == null || _account == null || _account.GameConf == null)
            {
                UiUtils.getInstance().info("还未初始化成功");
                return;
            }
            DialogResult result = MessageBox.Show("你确定要刷新立即重新登录吗?", "确认信息", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
            if (result == DialogResult.Yes) startRelogin();
        }
        private void menu_clearLog_Click(object sender, EventArgs e)
        {
            logText.Text = "";
            logSurpise.Text = "";
            logTemp.Text = "";
        }
        
        #region datagrid things
        private void dg_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Clicks < 2 && e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (e.ColumnIndex == 0 && e.RowIndex > -1)
                {
                    DataGridView dg = sender as DataGridView;
                    dg.DoDragDrop(dg.Rows[e.RowIndex], DragDropEffects.Move);
                }
            }
        }
        private void dg_DragDrop(object sender, DragEventArgs e)
        {
            DataGridView dg = sender as DataGridView;
            int selectindex = -1;
            if (_selectIndexes.ContainsKey(dg.Name)) selectindex = _selectIndexes[dg.Name];
            if (selectindex == -1) return;

            int dropindex = getDataGridRowIndexFromPoint(dg, e.X, e.Y);
            if (dropindex == -1) return;
            BindingSource src = dg.DataSource as BindingSource;
            object sel = src[selectindex];
            src.RemoveAt(selectindex);
            src.Insert(dropindex, sel);
        }
        private void dg_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }
        private Dictionary<string, int> _selectIndexes = new Dictionary<string,int>();
        private void dg_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.RowIndex > -1)
            {
                DataGridView dg = sender as DataGridView;
                if (!_selectIndexes.ContainsKey(dg.Name)) _selectIndexes.Add(dg.Name, e.RowIndex);
                else _selectIndexes[dg.Name] = e.RowIndex;
            }
        }
        private void dg_SelectionChanged(object sender, EventArgs e)
        {
            DataGridView dg = sender as DataGridView;
            int selectindex = -1;
            if(_selectIndexes.ContainsKey(dg.Name)) selectindex = _selectIndexes[dg.Name];
            if (dg.Rows.Count > 0 && dg.SelectedRows.Count > 0 && dg.SelectedRows[0].Index != selectindex)
            {
                if (dg.Rows.Count <= selectindex) selectindex = dg.Rows.Count - 1;
                dg.Rows[selectindex].Selected = true;
                dg.CurrentCell = dg.Rows[selectindex].Cells[0];
            }
        }
        private int getDataGridRowIndexFromPoint(DataGridView dg, int px, int py)
        {
            for (int i = 0, len = dg.Rows.Count; i < len; i++)
            {
                Rectangle rect = dg.GetRowDisplayRectangle(i, false);
                if (dg.RectangleToScreen(rect).Contains(px, py))
                {
                    return i;
                }
            }
            return -1;
        }
        private void dg_rowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
            DataGridView dg = sender as DataGridView;
            if (dg == null) return;
            BindingSource bsrc = dg.DataSource as BindingSource;
            if (bsrc == null) return;
            List<Equipment> src_eqp = bsrc.DataSource as List<Equipment>;
            List<Npc> src_npc = bsrc.DataSource as List<Npc>;
            if (src_eqp == null && src_npc == null) return;

            if (src_eqp != null && src_eqp.Count <= e.RowIndex) return;
            if (src_npc != null && src_npc.Count <= e.RowIndex) return;

            
            
            DataGridViewRow row = dg.Rows[e.RowIndex] as DataGridViewRow;
            if (src_eqp != null)
            {
                Equipment eqp = src_eqp[e.RowIndex] as Equipment;
                if (eqp.Quality == EquipmentQuality.White) row.DefaultCellStyle.ForeColor = Color.Black;
                else if (eqp.Quality == EquipmentQuality.Blue) row.DefaultCellStyle.ForeColor = Color.Blue;
                else if (eqp.Quality == EquipmentQuality.Green) row.DefaultCellStyle.ForeColor = Color.Green;
                else if (eqp.Quality == EquipmentQuality.Yellow) row.DefaultCellStyle.ForeColor = Color.Yellow;
                else if (eqp.Quality == EquipmentQuality.Red) row.DefaultCellStyle.ForeColor = Color.Red;
                else row.DefaultCellStyle.ForeColor = Color.Purple;
            }
            else if (src_npc != null)
            {
                Npc npc = src_npc[e.RowIndex] as Npc;
                string color = npc.ItemColor.TrimStart('#');
                if (color != "")
                {
                    Color _color = Color.FromArgb(
                        Int32.Parse(color.Substring(0, 2), NumberStyles.AllowHexSpecifier),
                        Int32.Parse(color.Substring(2, 2), NumberStyles.AllowHexSpecifier),
                        Int32.Parse(color.Substring(4, 2), NumberStyles.AllowHexSpecifier)
                        );
                    row.DefaultCellStyle.ForeColor = _color;
                }
            }
        }
        #endregion

        private void chk_selAll_building_CheckedChanged(object sender, EventArgs e)
        {
            object dtsrc = dg_buildings.DataSource;
            if (dtsrc == null) return;
            BindingSource bsrc = dtsrc as BindingSource;
            if (bsrc == null) return;
            List<Building> src = bsrc.DataSource as List<Building>;
            if (src == null) return;
            for(int i=0,len=src.Count; i<len; i++)
            {
                Building obj = src[i];
                if (obj == null) continue;
                obj.IsChecked = chk_selAll_building.Checked;
            }
            dg_buildings.Refresh();
        }
        private void dg_DataError(object sender, DataGridViewDataErrorEventArgs e) { }
        private void menu_login_Click(object sender, EventArgs e)
        {
            if (_account != null)
            {
                MessageBox.Show("小伙伴, 你已经登录了, 如果要更换账号的话, 还是关了再开吧, 要不就重新打开一个好了");
                return;
            }
            try
            {
                LoginForm frm = new LoginForm(this);
                frm.ShowDialog();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(String.Format("ERROR:{0}::{1}", ex.Message, ex.StackTrace));
            }
        }
        private void menu_exit_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("确认退出吗?", "确认退出", MessageBoxButtons.YesNo);
            if (result == System.Windows.Forms.DialogResult.Yes) { closeMe(); }
        }
        private void menu_about_Click(object sender, EventArgs e)
        {
            UiUtils.getInstance().info("本程序仅仅是为了个人测试代码架构设计, 如果冒犯了您的利益, 请立即与我联系, QQ:42817096");
        }
        private void menu_hideGame_Click(object sender, EventArgs e)
        {
            if (_gameurl == null || _gameurl == "")
            {
                UiUtils.getInstance().info("还未初始化");
                return;
            }
            if (gameBrowser.LocationURL.Equals(_initialUrl)) gameBrowser.Navigate(_gameurl);
            else gameBrowser.Navigate(_initialUrl);
        }
        private void notify_icon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (this.Visible) this.Hide();
            else { this.Show(); this.BringToFront(); }
        }        
        private void logText_LinkClicked(object sender, LinkClickedEventArgs e)
        {
            string text = e.LinkText;
            ReportViewer v = new ReportViewer();
            v.Show();
            v.BringToFront();
            v.setReport(text);
        }
        private void btn_attack_target_Click(object sender, EventArgs e)
        {
            AttackTargetSelector sel = new AttackTargetSelector();
            sel.StartPosition = FormStartPosition.Manual;
            sel.Location = new Point(500,400);
            sel.setCityInfo(_gameUser.getNewAreaCityInfo(), _gameUser._attack_selfCityId); 
            sel.ShowDialog();
            
            string cityname = sel.getCityname();
            lbl_attack_target.Text = cityname;
        }
        private void btn_weaponCalc_Click(object sender, EventArgs e)
        {
            WeaponCalc calc = new WeaponCalc();
            calc.StartPosition = FormStartPosition.CenterParent;
            calc.ShowDialog();
        }
        private void MainForm_Resize(object sender, EventArgs e)
        {
            lblStatus.Location = new Point(5, this.Height - 60);
            lbl_playerinfo.Location = new Point(200, this.Height - 60);
            mainTab.Width = this.Width - 20;
            mainTab.Height = lblStatus.Location.Y - 35;
            gameBrowser.Width = mainTab.Width - 15;
            gameBrowser.Height = mainTab.Height - 20;
        }
        private void btn_selNpc_Click(object sender, EventArgs e)
        {
            NpcSelector sel = new NpcSelector();
            sel.StartPosition = FormStartPosition.CenterParent;
            sel.setNpcs(_gameUser._all_npcs);
            sel.ShowDialog();

            Npc npc = sel.getSelectedNpc();
            string formation = sel.getFormation();
            if (npc == null) return;
            lbl_attackNpc.Text = String.Format("{0}:{1}:{2}:{3}", npc.Name, npc.ItemName, formation, npc.Id);
        }

        private void btn_selForceNpc_Click(object sender, EventArgs e)
        {
            NpcSelector sel = new NpcSelector();
            sel.StartPosition = FormStartPosition.CenterParent;
            sel.setNpcs(_gameUser._all_npcs);
            sel.ShowDialog();

            Npc npc = sel.getSelectedNpc();
            string formation = sel.getFormation();
            if (npc == null) return;
            lbl_attackForceNpc.Text = String.Format("{0}:{1}:{2}:{3}", npc.Name, npc.ItemName, formation, npc.Id);
        }
        #endregion

        #region temp server things
        private System.Threading.Thread _tempThread;
        private bool _doingTemp = false;
        private Timer _refreshTempTimer;
        private ITempExe _tempExe;
        public void addTempServer(string type, Dictionary<string, string> conf)
        {
            if (_tempExe != null)
            {
                UiUtils.getInstance().info("还有临时任务没有完成, 不能再开始新的临时任务");
                return;
            }
            if (type.Equals("campaign"))
            {
                _tempExe = new CampaignExe();
                _tempExe.setTarget(conf);
                lbl_tempStatus.Text = _tempExe.getStatus();
            }
            else if (type.Equals("equip_melt"))
            {
                _tempExe = new EquipMeltExe();
                _tempExe.setTarget(conf);
                lbl_tempStatus.Text = _tempExe.getStatus();
            }
            else if (type.Equals("wash"))
            {
                _tempExe = new CreditWashExe();
                _tempExe.setTarget(conf);
                lbl_tempStatus.Text = _tempExe.getStatus();
            }
            if (_tempExe == null) return;
            ILogger logger = new TempLogger(this);
            ProtocolMgr proto = new ProtocolMgr(_gameUser, logger, this, _gameurl, _jsessionid);
            _tempExe.setVariables(proto, logger, _gameUser, _account.GameConf);

            startTempServer();
        }
        private void btn_tempAdd_Click(object sender, EventArgs e)
        {
            if (_settingMgr == null)
            {
                UiUtils.getInstance().error("还未初始化服务");
                return;
            }
            TempServerForm frm = new TempServerForm(this);
            frm.ShowDialog();
        }
        private void btn_tempStop_Click(object sender, EventArgs e)
        {
            if (_settingMgr == null)
            {
                UiUtils.getInstance().error("还未初始化服务");
                return;
            }
            stopTempServer();
            _tempExe = null;
        }
        private void startTempServer()
        {
            stopTempServer();
            if (_tempExe == null) return;
            _refreshTempTimer = new Timer();
            _refreshTempTimer.Interval = 100;
            _refreshTempTimer.Tick += _refreshTempTimer_Tick;
            _refreshTempTimer.Start();
            _doingTemp = true;
            _tempThread = new System.Threading.Thread(_temp_thread_proc);
            _tempThread.Start();
            btn_tempAdd.Enabled = false;
            btn_tempStop.Enabled = true;
        }
        void _temp_thread_proc()
        {
            int counter = 0;
            if (_tempExe == null) return;
            long next_temp_time = _tempExe.execute();
            next_temp_time += TimeMgr.TimeStamp;
            while (_doingTemp)
            {
                if (_tempExe.isFinished()) break;
                if (counter < 20)
                {
                    System.Threading.Thread.Sleep(100);
                    counter++;
                    continue;
                }
                counter = 0;
                if (next_temp_time < TimeMgr.TimeStamp)
                {
                    next_temp_time = _tempExe.execute();
                    next_temp_time += TimeMgr.TimeStamp;
                }
            }
        }
        void _refreshTempTimer_Tick(object sender, EventArgs e)
        {
            if (_tempExe == null)
            {
                stopTempServer();
                return;
            }
            lbl_tempStatus.Text = _tempExe.getStatus();
            if (_tempExe.isFinished()) { stopTempServer(); _tempExe = null; }
        }
        private void stopTempServer()
        {
            _doingTemp = false;
            if (_refreshTempTimer != null && _refreshTempTimer.Enabled)
            {
                _refreshTempTimer.Stop();
                _refreshTempTimer.Dispose();
                _refreshTempTimer = null;
            }
            _tempThread = null;
            lbl_tempStatus.Text = "";
            btn_tempAdd.Enabled = true;
            btn_tempStop.Enabled = false;
        }
        private class TempLogger : ILogger
        {
            private MainForm _frm;
            public TempLogger(MainForm frm) { _frm = frm; }
            #region ILogger 成员

            public void logDebug(string text) { }
            public void logError(string text)
            {
                _frm.LogSafe(text, LogLevel.Error, Color.Red);
            }
            public void log(string text, Color color)
            {
                _frm.logTempSafe(text);
            }
            public void logSingle(string text) { }
            public void logSurprise(string text) { }
            #endregion
        }
        #endregion

        #region login and init game
        public void initializeComplete()
        {
            
        }
        private void menu_test_Click(object sender, EventArgs e)
        {
            ProtocolMgr proto = new ProtocolMgr(_gameUser, this, this, _gameurl, _jsessionid);
            ServiceFactory.getMiscManager().getPlayerInfo(proto, this, "", _gameUser);
            ServiceFactory.getMiscManager().getExtraInfo(proto, this, _gameUser);
            ServiceFactory.getMiscManager().getExtraInfo2(proto, this, _gameUser);
        }
        public void closeMe()
        {
            _intentExit = true;
            stopServer(true);
            _account = null;
            this.Close();
        }
        private bool _isRelogin = false;
        public void startRelogin()
        {
            _isRelogin = true;
            stop_relogin_timer();
            login_worker.CancelAsync();
            login_worker.RunWorkerAsync();
        }
        private void getCustomSession() 
        {
            if (_account == null || _account.Server_type != ServerType.Custom) return;
            string gameurl = _account.CustomGameUrl;
            if (gameurl.EndsWith("/")) gameurl = gameurl.Substring(0, gameurl.Length - 1);
            string gameRootUrl = gameurl + "/root/";
            subBrowser.Navigate(gameRootUrl); 
        }
        private LoginResult _login_result;
        private delegate void logMeDelegate(string logtext);
        private void logMeSafe(string logtext) 
        {
            if (logText.InvokeRequired) logText.Invoke(new logMeDelegate(logMe), logtext);
            else logMe(logtext);
        }
        private void logMe(string logtext)
        {
            string logt = String.Format("[{0:MM-dd HH:mm:ss}]: {1}", TimeMgr.DateTimeNow, logtext);
            logText.AppendText(logt);
            logText.Select(logText.Text.Length - logt.Length, logt.Length);
            logText.SelectionColor = Color.Red;
            logText.Select(logText.Text.Length, 0);
            logText.AppendText("\n");
            logText.ScrollToCaret();
        }
        private void login_worker_DoWork(object sender, DoWorkEventArgs e)
        {
            CommonReceiver recv = new CommonReceiver(_account, login_worker);
            if (_login_result != null && _login_result.StatusCode == LoginStatusCode.NeedVerifyCode)
            {
                logMeSafe("重新登录需要验证码呀大哥, 貌似你还是关了再重新打开才行");
                return;
            }
            else
            {
                List<Cookie> web_cookies = new List<Cookie>();
                _login_result = LoginMgr.getInstance().doLogin(recv, ref web_cookies);
            }
            e.Result = _login_result;
        }

        private void login_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            string state = e.UserState as string;
            if (state == null) return;
            logMeSafe(state);
        }

        private void login_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            LoginResult state = e.Result as LoginResult;
            if (state == null)
            {
                // 不停尝试重新登录, 直到用户关闭程序为止
                logMeSafe("重新登录失败");
                startReLoginTimerImpl(30);
                return;
            }
            string result_tip = state.StatusDesc;
            bool success = state.StatusCode == LoginStatusCode.Success;
            if (state.StatusCode == LoginStatusCode.NeedVerifyCode)
            {
                logMeSafe("重新登录需要验证码呀大哥, 貌似你还是关了再重新打开才行");
                return;
            }
            if (!success)
            {
                // 不停尝试重新登录, 直到用户关闭程序为止
                logMeSafe("重新登录失败");
                startReLoginTimerImpl(30);
                return;
            }
            initGame(_account, state);
        }
        private string _jsessionid = "";
        public string JSessionId { get { return _jsessionid; } }
        private string _gameurl = "";
        public string Gameurl { get { return _gameurl; } }
        public void initGame(AccountData acc, LoginResult state)
        {
            _account = acc;
            _exeMgr = new ExeMgr(_account.GameConf, _gameUser);
            _settingMgr = new SettingsMgr(_account.GameConf, _gameUser);
            _account.Status = AccountStatus.NotStart;
            if (_account.Server_type == ServerType.Custom)
            {
                gameBrowser.Navigate(_account.CustomLoginUrl);
                return;
            }

            string gameUrl = state.GameUrl;
            List<Cookie> collects = CommonUtils.getCookieByUrl(state.WebCookies, gameUrl);
            foreach (Cookie subcook in collects)
            {
                if (subcook == null) continue;
                CommonUtils.setCookie(gameUrl, subcook.Name, subcook.Value, subcook.Path, subcook.Domain, subcook.Expires);
            }
            Uri uri = new Uri(gameUrl);
            string host_url = String.Format("{0}://{1}/", uri.Scheme, uri.Host);
            CommonUtils.setCookie(host_url, "JSESSIONID", state.JSessionID, "/root/", uri.Host);

            _account.Cookies = state.WebCookies;
            _account.JsessionId = state.JSessionID;
            _account.GameUrl = state.GameUrl;

            _jsessionid = state.JSessionID;
            _gameurl = state.GameUrl;

            gameBrowser.Navigate(gameUrl);
            start_delay_init();
        }
        private void init_session()
        {
            try
            {
                ProtocolMgr proto = new ProtocolMgr(_gameUser, this, this, _gameurl, _jsessionid);
                ServiceFactory.getMiscManager().getServerTime(proto, this);
                int loaduser_result = ServiceFactory.getMiscManager().getPlayerInfo(proto, this, _account.RoleName, _gameUser);
                if (loaduser_result == 2) { UiUtils.getInstance().error("您选择的角色不存在"); return; }
                if (loaduser_result == 3) { UiUtils.getInstance().error("切换角色失败"); return; }
                if (loaduser_result == 4) { UiUtils.getInstance().error("角色被封号"); return; }
                if (loaduser_result == 1 || loaduser_result == 10) { UiUtils.getInstance().error("获取用户信息失败, 请重试"); return; }

                _account.GameConf = new GameConfig(EnumString.getString(_account.Server_type), _account.ServerId, _gameUser.Username);
                _account.GameConf.loadSettings();

                buildServers();
                _exeMgr.setExeVariables(proto, this, _gameUser, _account.GameConf);

                if (_logger == null) _logger = new LogHelper(EnumString.getString(_account.Server_type), _account.ServerId, _gameUser.Username);

                _exeMgr.init_data();

                init_completed();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(String.Format("ERROR::{0}::{1}", ex.Message, ex.StackTrace), "初始化出错了");
            }
            finally
            {
                _init_thread = null;
            }
        }
        private void buildServers()
        {
            if (GlobalConfig.getInstance().IsDebug)
            {
                #region debug
                _settingMgr.addSetting(new CommonServer(this));
                //_settingMgr.addSetting(new BuildingServer(this));
                //_settingMgr.addSetting(new HeroTrainServer(this));
                //_settingMgr.addSetting(new HeroWashServer(this));
                //_settingMgr.addSetting(new SecretaryServer(this));
                //_settingMgr.addSetting(new QhServer(this));
                //_settingMgr.addSetting(new MhServer(this));
                //_settingMgr.addSetting(new MerchantServer(this));
                //_settingMgr.addSetting(new DailyWeaponServer(this));
                //_settingMgr.addSetting(new WeaponServer(this));
                //_settingMgr.addSetting(new StoreServer(this));
                //_settingMgr.addSetting(new PolishServer(this));
                //_settingMgr.addSetting(new DinnerServer(this));
                //_settingMgr.addSetting(new FeteServer(this));
                //_settingMgr.addSetting(new ImposeServer(this));
                //_settingMgr.addSetting(new MarketServer(this));
                _settingMgr.addSetting(new MovableServer(this));
                //_settingMgr.addSetting(new StockServer(this));
                //_settingMgr.addSetting(new StoneServer(this));
                //_settingMgr.addSetting(new BattleServer(this));
                //_settingMgr.addSetting(new AttackServer(this));
                //_settingMgr.addSetting(new ArchServer(this));
                //_settingMgr.addSetting(new CrossPlatformCompeteServer(this));
                //_settingMgr.addSetting(new DailyTreasureGameServer(this));
                //_settingMgr.addSetting(new GemFlopServer(this));
                //_settingMgr.addSetting(new SilverFlopServer(this));
                //_settingMgr.addSetting(new JailEventServer(this));
                //_settingMgr.addSetting(new KfBanquetServer(this));
                //_settingMgr.addSetting(new GiftEventServer(this));
                //_settingMgr.addSetting(new PlayerCompeteServer(this));
                //_settingMgr.addSetting(new TreasureGameServer(this));
                //_settingMgr.addSetting(new WorldArmyServer(this));
                //_settingMgr.addSetting(new FestivalEventServer(this));

                _exeMgr.addExe(new CommonExe());
                //_exeMgr.addExe(new PingExe());
                //_exeMgr.addExe(new BuildingExe());
                //_exeMgr.addExe(new HeroTrainExe());
                //_exeMgr.addExe(new HeroWashExe());
                //_exeMgr.addExe(new SecretaryExe());
                //_exeMgr.addExe(new QhExe());
                //_exeMgr.addExe(new MhExe());
                //_exeMgr.addExe(new MerchantExe());
                //_exeMgr.addExe(new DailyWeaponExe());
                //_exeMgr.addExe(new WeaponExe());
                //_exeMgr.addExe(new StoreExe());
                //_exeMgr.addExe(new PolishExe());
                //_exeMgr.addExe(new DinnerExe());
                //_exeMgr.addExe(new FeteExe());
                //_exeMgr.addExe(new ImposeExe());
                //_exeMgr.addExe(new MarketExe());
                _exeMgr.addExe(new MovableExe());
                //_exeMgr.addExe(new StockExe());
                //_exeMgr.addExe(new StoneExe());
                //_exeMgr.addExe(new BattleExe());
                //_exeMgr.addExe(new AttackExe());
                //_exeMgr.addExe(new ArchExe());
                //_exeMgr.addExe(new CrossplatformCompeteExe());
                //_exeMgr.addExe(new DailyTreasureGameExe());
                //_exeMgr.addExe(new GemFlopExe());
                //_exeMgr.addExe(new SilverFlopExe());
                //_exeMgr.addExe(new JailEventExe());
                //_exeMgr.addExe(new KfBanquetExe());
                //_exeMgr.addExe(new GiftEventExe());
                //_exeMgr.addExe(new PlayerCompeteExe());
                //_exeMgr.addExe(new TreasureGameExe());
                //_exeMgr.addExe(new WorldArmyExe());
                //_exeMgr.addExe(new FestivalEventExe());
                #endregion

                return;
            }
            #region release
            _settingMgr.addSetting(new CommonServer(this));
            _settingMgr.addSetting(new BuildingServer(this));
            _settingMgr.addSetting(new HeroTrainServer(this));
            _settingMgr.addSetting(new HeroWashServer(this));
            _settingMgr.addSetting(new SecretaryServer(this));
            _settingMgr.addSetting(new QhServer(this));
            _settingMgr.addSetting(new MhServer(this));
            _settingMgr.addSetting(new MerchantServer(this));
            _settingMgr.addSetting(new DailyWeaponServer(this));
            _settingMgr.addSetting(new WeaponServer(this));
            _settingMgr.addSetting(new StoreServer(this));
            _settingMgr.addSetting(new PolishServer(this));
            _settingMgr.addSetting(new DinnerServer(this));
            _settingMgr.addSetting(new FeteServer(this));
            _settingMgr.addSetting(new ImposeServer(this));
            _settingMgr.addSetting(new MarketServer(this));
            _settingMgr.addSetting(new MovableServer(this));
            _settingMgr.addSetting(new StockServer(this));
            _settingMgr.addSetting(new StoneServer(this));
            _settingMgr.addSetting(new BattleServer(this));
            _settingMgr.addSetting(new AttackServer(this));
            _settingMgr.addSetting(new ArchServer(this));
            _settingMgr.addSetting(new CrossPlatformCompeteServer(this));
            _settingMgr.addSetting(new DailyTreasureGameServer(this));
            _settingMgr.addSetting(new GemFlopServer(this));
            _settingMgr.addSetting(new SilverFlopServer(this));
            _settingMgr.addSetting(new JailEventServer(this));
            _settingMgr.addSetting(new KfBanquetServer(this));
            _settingMgr.addSetting(new GiftEventServer(this));
            _settingMgr.addSetting(new PlayerCompeteServer(this));
            _settingMgr.addSetting(new TreasureGameServer(this));
            _settingMgr.addSetting(new WorldArmyServer(this));
            _settingMgr.addSetting(new FestivalEventServer(this));

            _exeMgr.addExe(new PingExe());
            _exeMgr.addExe(new CommonExe());
            _exeMgr.addExe(new BuildingExe());
            _exeMgr.addExe(new HeroTrainExe());
            _exeMgr.addExe(new HeroWashExe());
            _exeMgr.addExe(new SecretaryExe());
            _exeMgr.addExe(new QhExe());
            _exeMgr.addExe(new MhExe());
            _exeMgr.addExe(new MerchantExe());
            _exeMgr.addExe(new DailyWeaponExe());
            _exeMgr.addExe(new WeaponExe());
            _exeMgr.addExe(new StoreExe());
            _exeMgr.addExe(new PolishExe());
            _exeMgr.addExe(new DinnerExe());
            _exeMgr.addExe(new FeteExe());
            _exeMgr.addExe(new ImposeExe());
            _exeMgr.addExe(new MarketExe());
            _exeMgr.addExe(new MovableExe());
            _exeMgr.addExe(new StockExe());
            _exeMgr.addExe(new StoneExe());
            _exeMgr.addExe(new BattleExe());
            _exeMgr.addExe(new AttackExe());
            _exeMgr.addExe(new ArchExe());
            _exeMgr.addExe(new CrossplatformCompeteExe());
            _exeMgr.addExe(new DailyTreasureGameExe());
            _exeMgr.addExe(new GemFlopExe());
            _exeMgr.addExe(new SilverFlopExe());
            _exeMgr.addExe(new JailEventExe());
            _exeMgr.addExe(new KfBanquetExe());
            _exeMgr.addExe(new GiftEventExe());
            _exeMgr.addExe(new PlayerCompeteExe());
            _exeMgr.addExe(new TreasureGameExe());
            _exeMgr.addExe(new WorldArmyExe());
            _exeMgr.addExe(new FestivalEventExe());
            #endregion
        }
        private void init_data()
        {
            try
            {
                if (_exeMgr == null) return;
                _exeMgr.init_data();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(String.Format("ERROR::{0}::{1}", ex.Message, ex.StackTrace), "初始化出错了");
            }
            finally
            {
                _init_thread = null;
            }
        }
        private void start_delay_init(bool is_only_init_data=false)
        {
            if (_init_thread == null)
            {
                if (is_only_init_data) _init_thread = new System.Threading.Thread(init_data);
                else _init_thread = new System.Threading.Thread(init_session);
                _init_thread.Start();
            }
        }
        #endregion

        #region relogin things
        public void startReLoginTimerImpl(int waitSeconds=1800)
        {
            if (waitSeconds == 0) { startRelogin(); return; }
            if (_relogin_timer != null) return;
            logMeSafe(String.Format("将在{0}后开始重新登录", waitSeconds >= 60 ? String.Format("{0}分钟", waitSeconds / 60) : String.Format("{0}秒", waitSeconds)));
            start_relogin_timer(waitSeconds);
        }
        private void tmr_relogin_Tick(object sender, EventArgs e)
        {
            stop_relogin_timer();
            startRelogin();
        }
        private void start_relogin_timer(int waitSeconds)
        {
            stop_relogin_timer();
            _relogin_timer = new System.Timers.Timer();
            _relogin_timer.Interval = waitSeconds * 1000;
            _relogin_timer.Elapsed += tmr_relogin_Tick;
            _relogin_timer.Start();
        }
        private void stop_relogin_timer()
        {
            if (_relogin_timer != null)
            {
                _relogin_timer.Stop();
                _relogin_timer = null;
            }
        }
        #endregion

        #region ILogger 成员

        public void logDebug(string text)
        {
            LogSafe(text, LogLevel.Debug, Color.Blue);
        }

        public void logError(string text)
        {
            LogSafe(text, LogLevel.Error, Color.Red);
        }

        public void log(string text, Color color)
        {
            LogSafe(text, LogLevel.Info, color);
        }

        public void logSingle(string text)
        {
            LogSingleSafe(text);
        }

        public void logSurprise(string text)
        {
            logSurpriseSafe(text, Color.Black);
        }
        protected enum LogLevel
        {
            Debug, Info, Error
        }
        
        private delegate void LogSingleDelegate(string logtext);
        private LogSingleDelegate _logSingleDelegate;
        public void LogSingleSafe(string logtext)
        {
            if (_logSingleDelegate == null) _logSingleDelegate = new LogSingleDelegate(LogSingle);
            if (lblStatus.InvokeRequired) lblStatus.Invoke(_logSingleDelegate, logtext);
            else LogSingle(logtext);
        }
        internal void LogSingle(string logtext)
        {
            lblStatus.Text = logtext;
        }
        public void LogDebug(string logtext) { LogSafe(logtext, LogLevel.Debug, Color.Gray); }
        public void LogInfo(string logtext, Color logColor) { LogSafe(logtext, LogLevel.Info, logColor); }
        public void LogError(string logtext) { LogSafe(logtext, LogLevel.Error, Color.Red); }

        private delegate void LogDelegate(string logtext, LogLevel level, Color logColor);
        private LogDelegate _logDelegate;
        protected void LogSafe(string logtext, LogLevel level, Color logColor)
        {
            if (_logDelegate == null) _logDelegate = new LogDelegate(Log);
            if (logText.InvokeRequired) logText.Invoke(_logDelegate, logtext, level, logColor);
            else Log(logtext, level, logColor);
        }
        protected void Log(string logtext, LogLevel level, Color logColor)
        {
            if (level < _logLevel) return;
            string logt = String.Format("[{0:MM-dd HH:mm:ss}]: {1}", TimeMgr.DateTimeNow, logtext);
            if (_logger != null) _logger.log(logt);
            if (level > LogLevel.Debug)
            {
                logText.AppendText(logt);
                logText.Select(logText.Text.Length - logt.Length, logt.Length);
                logText.SelectionColor = logColor;
                logText.Select(logText.Text.Length, 0);
                logText.AppendText("\n");
                logText.ScrollToCaret();
            }
        }
        protected void LogFile(string logtext)
        {
            string logt = String.Format("[{0:MM-dd HH:mm:ss}]: {1}", TimeMgr.DateTimeNow, logtext);
            if (_logger != null) _logger.log(logt);
        }
        private delegate void LogSurpriseDelegate(string logtext, Color logColor);
        private LogSurpriseDelegate _logSurpriseDelegate;
        protected void logSurpriseSafe(string logtext, Color logColor)
        {
            if (_logSurpriseDelegate == null) _logSurpriseDelegate = new LogSurpriseDelegate(LogSurprise);
            if (logSurpise.InvokeRequired) logSurpise.Invoke(_logSurpriseDelegate, logtext, logColor);
            else LogSurprise(logtext, logColor);
        }
        public void LogSurprise(string logtext, Color logColor)
        {
            string logt = String.Format("[{0:MM-dd HH:mm:ss}]: {1}", DateTime.Now, logtext);
            logSurpise.AppendText(logt);
            logSurpise.Select(logSurpise.Text.Length - logt.Length, logt.Length);
            logSurpise.SelectionColor = logColor;
            logSurpise.Select(logSurpise.Text.Length, 0);
            logSurpise.AppendText("\n");
            logSurpise.ScrollToCaret();
        }
        public void LogTemp(string logtext) { logTempSafe(logtext); }
        private delegate void logTempDelegate(string text);
        private logTempDelegate _logTempSafe;
        private void logTempSafe(string text)
        {
            if (_logTempSafe == null) _logTempSafe = new logTempDelegate(logTemperory);
            if (logTemp.InvokeRequired) logTemp.Invoke(_logTempSafe, text);
            else logTemperory(text);
        }
        private void logTemperory(string text)
        {
            string logt = String.Format("[{0:MM-dd HH:mm:ss}]: {1}", TimeMgr.DateTimeNow, text);
            if (_logger != null) _logger.log(logt);
            logTemp.AppendText(logt);
            logTemp.AppendText("\n");
            logTemp.ScrollToCaret();
        }
        #endregion

        #region IServer 成员

        public void init_completed()
        {
            if (_isRelogin) { startServer(); }
            else
            {
                _serverStatus = 1;
                LogSingleSafe("挂机就绪");
            }
        }
        private bool _server_running = false;
        private void _exe_proc()
        {
            int counter = 0;
            while (_server_running)
            {
                if (_exeMgr == null) { System.Threading.Thread.Sleep(100); continue; }
                try 
                {
                    if (counter < 20) { counter++; System.Threading.Thread.Sleep(100); continue; }
                    counter = 0;
                    _exeMgr.fire();
                    LogSingleSafe("挂机中...");
                }
                catch (System.Threading.ThreadInterruptedException intere) { Console.WriteLine(intere); }
                catch (Exception ex) { LogFile(String.Format("error:{0}:{1}", ex.Message, ex.StackTrace)); }
            }
        }

        public void startServer()
        {
            stopServer();
            _server_running = true;
            _exeMgr.clear_runtime();
            _exe_thread = new System.Threading.Thread(_exe_proc);
            _exe_thread.Start();
            _serverStatus = 2;
        }

        public void stopServer(bool is_user_operate = false)
        {
            _server_running = false;
            if (_exe_thread != null)
            {
                try
                {
                    _exe_thread.Join(0);
                    _exe_thread.Interrupt();
                    _exe_thread = null;
                }
                catch { }
            }
            if (is_user_operate)
            {
                _serverStatus = 3;
                _isRelogin = false;
            }
            else
            {
                _serverStatus = 3;
                _isRelogin = true;
            }
        }

        public void startReLoginTimer()
        {
            startReLoginTimerImpl();
        }

        public void refreshPlayerSafe()
        {
            _gameUser.addUiToQueue(ConfigStrings.S_Global);
        }

        #endregion
    }
}
